package hawk.example.bookstore.sql.provider;

import static glz.hawkframework.mybatis.writer.MybatisBuilderContextImpl.*;
import static glz.hawkframework.sql.support.impl.DSL.*;
import static glz.hawkframework.support.ArgumentSupport.*;
import static glz.hawkframework.support.LogicSupport.*;
import static hawk.example.bookstore.support.BookAuthorMapSupport.*;

import glz.hawkframework.helper.ObjectHelper;
import glz.hawkframework.mybatis.sql.MybatisParam;
import glz.hawkframework.mybatis.sql.provider.AbstractSqlProvider;
import glz.hawkframework.mybatis.statement.GeneralStatementProvider;
import glz.hawkframework.mybatis.statement.InsertStatementProvider;
import glz.hawkframework.mybatis.statement.MultiRowsInsertStatementProvider;
import glz.hawkframework.mybatis.statement.UpdateStatementProvider;
import glz.hawkframework.mybatis.statement.impl.GeneralStatementProviderImpl;
import glz.hawkframework.mybatis.statement.impl.InsertStatementProviderImpl;
import glz.hawkframework.mybatis.statement.impl.MultiRowsInsertStatementProviderImpl;
import glz.hawkframework.mybatis.statement.impl.UpdateStatementProviderImpl;
import glz.hawkframework.mybatis.writer.MybatisBuilderContext;
import glz.hawkframework.sql.condition.Condition;
import glz.hawkframework.sql.dsl.delete.Delete;
import glz.hawkframework.sql.dsl.insert.Insert;
import glz.hawkframework.sql.dsl.select.Select;
import glz.hawkframework.sql.dsl.update.Update;
import glz.hawkframework.sql.support.SqlBuilder;
import glz.hawkframework.sql.support.impl.DefaultAliasedNamedColumn;
import glz.hawkframework.sql.util.QueryWrapper;

import hawk.example.bookstore.po.BookAuthorMapPo;
import hawk.example.bookstore.update.BookAuthorMapColumnUpdate;
import hawk.example.bookstore.update.BookAuthorMapUpdate;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.builder.annotation.ProviderMethodResolver;
import org.springframework.stereotype.Component;

@Component
public class BookAuthorMapSqlProvider extends AbstractSqlProvider implements ProviderMethodResolver {
    public BookAuthorMapSqlProvider(SqlBuilder<MybatisBuilderContext> sqlBuilder) {
        super(sqlBuilder);
    }

    protected Insert buildInsert() {
        return insertInto(BOOK_AUTHOR_MAP, COLUMNS).values(Arrays.stream(PARAM_COLUMNS).map(p->p.prefix(InsertStatementProvider.PARAM_PREFIX)).toArray()).build();
    }

    public InsertStatementProvider<BookAuthorMapPo> insert(BookAuthorMapPo bookAuthorMapPo) {
        String key = buildKey("insert", BookAuthorMapPo.class);
        String insertSql = sqlCache.computeIfAbsent(key, k -> sqlBuilder.build(buildInsert(), DUMMY_INSTANCE));
        return InsertStatementProviderImpl.builder(insertSql, bookAuthorMapPo).build();
    }

    protected Insert buildInsertSelective(BookAuthorMapPo bookAuthorMapPo) {
        List<DefaultAliasedNamedColumn> columns = new ArrayList<>();
        List<MybatisParam> params = new ArrayList<>();
        if (bookAuthorMapPo.getBookAuthorMapId() != null) {columns.add(BOOK_AUTHOR_MAP_ID); params.add(PARAM_BOOK_AUTHOR_MAP_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getAuthorId() != null) {columns.add(AUTHOR_ID); params.add(PARAM_AUTHOR_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getBookId() != null) {columns.add(BOOK_ID); params.add(PARAM_BOOK_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getCreateDateTime() != null) {columns.add(CREATE_DATE_TIME); params.add(PARAM_CREATE_DATE_TIME.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getUpdateDateTime() != null) {columns.add(UPDATE_DATE_TIME); params.add(PARAM_UPDATE_DATE_TIME.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getDeleteDateTime() != null) {columns.add(DELETE_DATE_TIME); params.add(PARAM_DELETE_DATE_TIME.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getCreateUserId() != null) {columns.add(CREATE_USER_ID); params.add(PARAM_CREATE_USER_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getUpdateUserId() != null) {columns.add(UPDATE_USER_ID); params.add(PARAM_UPDATE_USER_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getDeleteUserId() != null) {columns.add(DELETE_USER_ID); params.add(PARAM_DELETE_USER_ID.prefix(InsertStatementProvider.PARAM_PREFIX));}
        if (bookAuthorMapPo.getRecordVersion() != null) {columns.add(RECORD_VERSION); params.add(PARAM_RECORD_VERSION.prefix(InsertStatementProvider.PARAM_PREFIX));}
        return insertInto(BOOK_AUTHOR_MAP, columns.toArray(new DefaultAliasedNamedColumn[0])).values(params.toArray(new MybatisParam[0])).build();
    }

    public InsertStatementProvider<BookAuthorMapPo> insertSelective(BookAuthorMapPo bookAuthorMapPo) {
        String insertSql = sqlBuilder.build(buildInsertSelective(bookAuthorMapPo), DUMMY_INSTANCE);
        return InsertStatementProviderImpl.builder(insertSql, bookAuthorMapPo).build();
    }

    protected Insert buildInsertMultiple(List<BookAuthorMapPo> bookAuthorMapPos) {
        MybatisParam[][] paramses = new MybatisParam[bookAuthorMapPos.size()][10];
        for (int i = 0; i < bookAuthorMapPos.size(); i++) {
            MybatisParam[] params = new MybatisParam[10];
            params[0] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_BOOK_AUTHOR_MAP_ID.getParamName()) , PARAM_BOOK_AUTHOR_MAP_ID.getJdbcType()).build();
            params[1] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_AUTHOR_ID.getParamName()) , PARAM_AUTHOR_ID.getJdbcType()).build();
            params[2] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_BOOK_ID.getParamName()) , PARAM_BOOK_ID.getJdbcType()).build();
            params[3] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_CREATE_DATE_TIME.getParamName()) , PARAM_CREATE_DATE_TIME.getJdbcType()).build();
            params[4] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_UPDATE_DATE_TIME.getParamName()) , PARAM_UPDATE_DATE_TIME.getJdbcType()).build();
            params[5] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_DELETE_DATE_TIME.getParamName()) , PARAM_DELETE_DATE_TIME.getJdbcType()).build();
            params[6] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_CREATE_USER_ID.getParamName()) , PARAM_CREATE_USER_ID.getJdbcType()).build();
            params[7] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_UPDATE_USER_ID.getParamName()) , PARAM_UPDATE_USER_ID.getJdbcType()).build();
            params[8] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_DELETE_USER_ID.getParamName()) , PARAM_DELETE_USER_ID.getJdbcType()).build();
            params[9] = MybatisParam.builder(String.format("%s[%d].%s", MultiRowsInsertStatementProvider.PARAM_PREFIX, i, PARAM_RECORD_VERSION.getParamName()) , PARAM_RECORD_VERSION.getJdbcType()).build();
            paramses[i] = params;
        }
        return insertInto(BOOK_AUTHOR_MAP, COLUMNS).valueses(paramses).build();
    }

    public MultiRowsInsertStatementProvider<BookAuthorMapPo> insertMultiple(List<BookAuthorMapPo> bookAuthorMapPos) {
        String insertSql = sqlBuilder.build(buildInsertMultiple(bookAuthorMapPos), DUMMY_INSTANCE);
        return MultiRowsInsertStatementProviderImpl.builder(insertSql, bookAuthorMapPos).build();
    }

    public static Delete buildDeleteByPrimaryKey() {
        return deleteFrom(BOOK_AUTHOR_MAP).where(BOOK_AUTHOR_MAP_ID.eq(PARAM_BOOK_AUTHOR_MAP_ID.prefix(GeneralStatementProvider.PARAM_PREFIX)), and(RECORD_VERSION.eq(PARAM_RECORD_VERSION.prefix(GeneralStatementProvider.PARAM_PREFIX)))).build();
    }

    public GeneralStatementProvider deleteByPrimaryKey(BigInteger bookAuthorMapId, Long recordVersion) {
        String key = buildKey("deleteByPrimaryKey", BigInteger.class, Long.class);
        String deleteSql = sqlCache.computeIfAbsent(key, k -> sqlBuilder.build(buildDeleteByPrimaryKey(), DUMMY_INSTANCE));
        return GeneralStatementProviderImpl.builder(deleteSql).addParam("bookAuthorMapId", argNotNull(bookAuthorMapId, "bookAuthorMapId")).addParam("recordVersion", argNotNull(recordVersion, "recordVersion")).build();
    }

    protected Update buildUpdateByPrimaryKey(BookAuthorMapUpdate bookAuthorMapUpdate) {
        return update(BOOK_AUTHOR_MAP)
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isBookAuthorMapIdUpdated, () -> c.set(BOOK_AUTHOR_MAP_ID, PARAM_BOOK_AUTHOR_MAP_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isAuthorIdUpdated, () -> c.set(AUTHOR_ID, PARAM_AUTHOR_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isBookIdUpdated, () -> c.set(BOOK_ID, PARAM_BOOK_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isCreateDateTimeUpdated, () -> c.set(CREATE_DATE_TIME, PARAM_CREATE_DATE_TIME.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isUpdateDateTimeUpdated, () -> c.set(UPDATE_DATE_TIME, PARAM_UPDATE_DATE_TIME.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isDeleteDateTimeUpdated, () -> c.set(DELETE_DATE_TIME, PARAM_DELETE_DATE_TIME.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isCreateUserIdUpdated, () -> c.set(CREATE_USER_ID, PARAM_CREATE_USER_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isUpdateUserIdUpdated, () -> c.set(UPDATE_USER_ID, PARAM_UPDATE_USER_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isDeleteUserIdUpdated, () -> c.set(DELETE_USER_ID, PARAM_DELETE_USER_ID.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .set(c -> consumeIfTrue(bookAuthorMapUpdate::isRecordVersionUpdated, () -> c.set(RECORD_VERSION, PARAM_RECORD_VERSION.prefix(UpdateStatementProvider.UPDATE_PARAM_PREFIX))))
            .where(BOOK_AUTHOR_MAP_ID.eq(PARAM_BOOK_AUTHOR_MAP_ID.prefix(UpdateStatementProvider.UPDATE_CONDITION_PREFIX)), and(RECORD_VERSION.eq(PARAM_RECORD_VERSION.prefix(UpdateStatementProvider.UPDATE_CONDITION_PREFIX))))
            .build();
    }

    public UpdateStatementProvider updateByPrimaryKey(BookAuthorMapUpdate bookAuthorMapUpdate, BigInteger bookAuthorMapId, Long recordVersion) {
        String updateSql = sqlBuilder.build(buildUpdateByPrimaryKey(bookAuthorMapUpdate), DUMMY_INSTANCE);
        return UpdateStatementProviderImpl.builder(updateSql, bookAuthorMapUpdate).addParam("bookAuthorMapId", argNotNull(bookAuthorMapId, "bookAuthorMapId")).addParam("recordVersion", argNotNull(recordVersion, "recordVersion")).build();
    }

    protected Select buildSelectByPrimaryKey() {
        return select(COLUMNS).from(BOOK_AUTHOR_MAP).where(BOOK_AUTHOR_MAP_ID.eq(PARAM_BOOK_AUTHOR_MAP_ID.prefix(GeneralStatementProvider.PARAM_PREFIX))).build();
    }

    public GeneralStatementProvider selectByPrimaryKey(BigInteger bookAuthorMapId) {
        String key = buildKey("selectByPrimaryKey", BigInteger.class);
        String selectSql = sqlCache.computeIfAbsent(key, k -> sqlBuilder.build(buildSelectByPrimaryKey(), DUMMY_INSTANCE));
        return GeneralStatementProviderImpl.builder(selectSql).addParam("bookAuthorMapId", argNotNull(bookAuthorMapId, "bookAuthorMapId")).build();
    }

    protected Select buildCuntByPrimaryKey() {
        return selectCount().from(BOOK_AUTHOR_MAP).where(BOOK_AUTHOR_MAP_ID.eq(PARAM_BOOK_AUTHOR_MAP_ID.prefix(GeneralStatementProvider.PARAM_PREFIX))).build();
    }

    public GeneralStatementProvider countByPrimaryKey(BigInteger bookAuthorMapId) {
        String key = buildKey("countByPrimaryKey", BigInteger.class);
        String selectSql = sqlCache.computeIfAbsent(key, k -> sqlBuilder.build(buildCuntByPrimaryKey(), DUMMY_INSTANCE));
        return GeneralStatementProviderImpl.builder(selectSql).addParam("bookAuthorMapId", argNotNull(bookAuthorMapId, "bookAuthorMapId")).build();
    }

    public static Select buildSelectOrCountDynamic(QueryWrapper queryWrapper) {
        return select(queryWrapper.isCount(), queryWrapper.isDistinct(), ObjectHelper.isEmpty(queryWrapper.getColumns()) ? COLUMNS : queryWrapper.getColumns())
            .from(BOOK_AUTHOR_MAP)
            .where(queryWrapper.getCondition())
            .orderBy(ObjectHelper.isNotEmpty(queryWrapper.getOrderColumns()), queryWrapper.getOrderColumns())
            .limit(queryWrapper.getLimit() != null && !queryWrapper.isCount(), queryWrapper.getLimit())
            .offset(queryWrapper.getOffset() != null && !queryWrapper.isCount(), queryWrapper.getOffset())
            .forUpdate(queryWrapper.isForUpdate() && !queryWrapper.isCount())
            .build();
    }

    public GeneralStatementProvider selectOrCountDynamic(QueryWrapper queryWrapper) {
        return generalSelect(buildSelectOrCountDynamic(queryWrapper));
    }

    public static Delete buildDeleteDynamic(Condition condition) {
        return deleteFrom(BOOK_AUTHOR_MAP).where(condition).build();
    }

    public GeneralStatementProvider deleteDynamic(Condition condition) {
        return generalDelete(buildDeleteDynamic(condition));
    }

    public static Update buildUpdateDynamic(BookAuthorMapColumnUpdate bookAuthorMapColumnUpdate, Condition condition) {
        return update(BOOK_AUTHOR_MAP)
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isBookAuthorMapIdUpdated, () -> c.set(BOOK_AUTHOR_MAP_ID, bookAuthorMapColumnUpdate.getBookAuthorMapId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isAuthorIdUpdated, () -> c.set(AUTHOR_ID, bookAuthorMapColumnUpdate.getAuthorId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isBookIdUpdated, () -> c.set(BOOK_ID, bookAuthorMapColumnUpdate.getBookId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isCreateDateTimeUpdated, () -> c.set(CREATE_DATE_TIME, bookAuthorMapColumnUpdate.getCreateDateTime())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isUpdateDateTimeUpdated, () -> c.set(UPDATE_DATE_TIME, bookAuthorMapColumnUpdate.getUpdateDateTime())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isDeleteDateTimeUpdated, () -> c.set(DELETE_DATE_TIME, bookAuthorMapColumnUpdate.getDeleteDateTime())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isCreateUserIdUpdated, () -> c.set(CREATE_USER_ID, bookAuthorMapColumnUpdate.getCreateUserId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isUpdateUserIdUpdated, () -> c.set(UPDATE_USER_ID, bookAuthorMapColumnUpdate.getUpdateUserId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isDeleteUserIdUpdated, () -> c.set(DELETE_USER_ID, bookAuthorMapColumnUpdate.getDeleteUserId())))
            .set(c -> consumeIfTrue(bookAuthorMapColumnUpdate::isRecordVersionUpdated, () -> c.set(RECORD_VERSION, bookAuthorMapColumnUpdate.getRecordVersion())))
            .where(condition)
            .build();
    }

    public GeneralStatementProvider updateDynamic(BookAuthorMapColumnUpdate bookAuthorMapColumnUpdate, Condition condition) {
        return generalUpdate(buildUpdateDynamic(bookAuthorMapColumnUpdate, condition));
    }
}
